﻿using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Collections;
using System.IO;
using System.Text.RegularExpressions;
using System.Runtime.Serialization;
using System.Security.Permissions;
using System.Runtime.InteropServices;

namespace Heaven.Mathematics
{
    /// <summary>
    /// Четырехмерный мерный вектор
    /// </summary>
    [Serializable]
    public struct Vector4 : ICloneable
    {
        #region Атрибуты

        private double x;
        private double y;
        private double z;
        private double w;

        #endregion

        #region Конструкторы

        /// <summary>
        /// Инициализация вектора путём задания его координат
        /// </summary>
        /// <param name="x">Скаляр, Х координата</param>
        /// <param name="y">Скаляр, Y координата</param>
        /// <param name="z">Скаляр, Z координата</param>
        /// <param name="w">Скаляр, W координата</param>
        public Vector4(double x, double y, double z, double w)
        {
            this.x = x;
            this.y = y;
            this.z = z;
            this.w = w;
        }

        /// <summary>
        /// Инициализация вектора путём задания его координат в массиве
        /// </summary>
        /// <param name="coordinates">Массив содержащий координаты вектора >= 4</param>
        public Vector4(double[] coordinates)
        {
            Debug.Assert(coordinates != null);
            Debug.Assert(coordinates.Length >= 4);

            x = coordinates[0];
            y = coordinates[1];
            z = coordinates[2];
            w = coordinates[3];
        }

        /// <summary>
        /// Конструктор копирования
        /// </summary>
        /// <param name="vector">Вектор, координаты которого будут использованы для инициализации</param>
        public Vector4(Vector4 vector)
        {
            x = vector.X;
            y = vector.Y;
            z = vector.Z;
            w = vector.W;
        }

        /// <summary>
        /// Конструктор копирования
        /// </summary>
        /// <param name="vector">Вектор, координаты которого будут использованы для инициализации</param>
        /// <param name="w">Четвертая координата</param>
        public Vector4(Vector3 vector, double w)
        {
            x = vector.X;
            y = vector.Y;
            z = vector.Z;
            this.w = w;
        }

        #endregion

        #region Константы

        /// <summary>
        /// Нулевой вектор
        /// </summary>
        public static readonly Vector4 Zero = new Vector4(0.0f, 0.0f, 0.0f, 0.0f);
        /// <summary>
        /// Ось абсцисс
        /// </summary>
        public static readonly Vector4 XAxis = new Vector4(1.0f, 0.0f, 0.0f, 0.0f);
        /// <summary>
        /// Ось ординат
        /// </summary>
        public static readonly Vector4 YAxis = new Vector4(0.0f, 1.0f, 0.0f, 0.0f);
        /// <summary>
        /// Ось аппликат
        /// </summary>
        public static readonly Vector4 ZAxis = new Vector4(0.0f, 0.0f, 1.0f, 0.0f);
        /// <summary>
        /// Ось W
        /// </summary>
        public static readonly Vector4 WAxis = new Vector4(0.0f, 0.0f, 0.0f, 1.0f);

        #endregion

        #region Свойства

        /// <summary>
        /// Получение или установка абсциссы
        /// </summary>
        /// <value>Абсцисса этого вектора</value>
        public double X
        {
            get { return x; }
            set { x = value; }
        }
        /// <summary>
        /// Получение или установка ординаты
        /// </summary>
        /// <value>Ордината этого вектора</value>
        public double Y
        {
            get { return y; }
            set { y = value; }
        }
        /// <summary>
        /// Получение или установка аппликаты
        /// </summary>
        /// <value>Аппликата этого вектора</value>
        public double Z
        {
            get { return z; }
            set { z = value; }
        }
        /// <summary>
        /// Получение и установка W-координаты вектора
        /// </summary>
        /// <value>W-координата вектора</value>
        public double W
        {
            get { return w; }
            set { w = value; }
        }

        #endregion

        #region Методы клонирования

        /// <summary>
        /// Создание точной копии этого объекта
        /// </summary>
        /// <returns>Клон этого объекта</returns>
        object ICloneable.Clone()
        {
            return new Vector4(this);
        }

        /// <summary>
        /// Создание точной копии этого вектора
        /// </summary>
        /// <returns>Клон этого вектора</returns>
        public Vector4 Clone()
        {
            return new Vector4(this);
        }

        #endregion

        #region Статические методы

        /// <summary>
        /// Сложение двух векторов
        /// </summary>
        /// <param name="v">Слагаемый вектор Vector4</param>
        /// <param name="w">Слагаемый вектор Vector4</param>
        /// <returns></returns>
        public static Vector4 Add(Vector4 v, Vector4 w)
        {
            return new Vector4(v.X + w.X, v.Y + w.Y, v.Z + w.Z, v.W + w.W);
        }

        /// <summary>
        /// Сложение вектора и скаляра
        /// </summary>
        /// <param name="v">Слагаемый вектор</param>
        /// <param name="s">Слагаемый скаляр</param>
        /// <returns>Результирующий вектор суммы = v + s</returns>
        public static Vector4 Add(Vector4 v, double s)
        {
            return new Vector4(v.X + s, v.Y + s, v.Z + s, v.W + s);
        }

        /// <summary>
        /// Сложение двух векторов, результат записывается в третий
        /// </summary>
        /// <param name="u">Слагаемый вектор</param>
        /// <param name="v">Слагаемый вектор</param>
        /// <param name="w">Вектор для помещения суммы</param>
        public static void Add(Vector4 u, Vector4 v, ref Vector4 w)
        {
            w.X = u.X + v.X;
            w.Y = u.Y + v.Y;
            w.Z = u.Z + v.Z;
            w.W = u.W + v.W;
        }

        /// <summary>
        /// Сложение вектора со скаляром и помещение результата в другой вектор
        /// </summary>
        /// <param name="u">Слагаемый вектор</param>
        /// <param name="s">Слагаемый скаляр</param>
        /// <param name="v">Вектор - приёмник суммы</param>
        public static void Add(Vector4 u, double s, ref Vector4 v)
        {
            v.X = u.X + s;
            v.Y = u.Y + s;
            v.Z = u.Z + s;
            v.W = u.W + s;
        }

        /// <summary>
        /// Разница двух векторов
        /// </summary>
        /// <param name="v">Уменьшаемый вектор</param>
        /// <param name="w">Вычитаемый вектор</param>
        /// <returns>Разница двух векторов</returns>
        /// <remarks>
        ///	result[i] = v[i] - w[i].
        /// </remarks>
        public static Vector4 Subtract(Vector4 v, Vector4 w)
        {
            return new Vector4(v.X - w.X, v.Y - w.Y, v.Z - w.Z, v.W - w.W);
        }

        /// <summary>
        /// Вычитание скаляра из вектора
        /// </summary>
        /// <param name="v">Уменьшаемый вектор</param>
        /// <param name="s">Вычитаемый скаляр</param>
        /// <returns>Разница вектора и скаляра</returns>
        /// <remarks>
        /// result[i] = v[i] - s
        /// </remarks>
        public static Vector4 Subtract(Vector4 v, double s)
        {
            return new Vector4(v.X - s, v.Y - s, v.Z - s, v.W - s);
        }

        /// <summary>
        /// Вычитание вектора из скаляра  
        /// </summary>
        /// <param name="s">Уменьшаемый скаляр (по сути вектор (s,s,s,s))</param>
        /// <param name="v">Вычитаемый вектор</param>
        /// <returns>Разница скаляра и вектора</returns>
        /// <remarks>
        /// result[i] = s - v[i]
        /// </remarks>
        public static Vector4 Subtract(double s, Vector4 v)
        {
            return new Vector4(s - v.X, s - v.Y, s - v.Z, s - v.W);
        }

        /// <summary>
        /// Разница векторов с помещением результата в третий
        /// </summary>
        /// <param name="u">Уменьшаемый вектор</param>
        /// <param name="v">Вычитаемы вектор</param>
        /// <param name="w">Вектор, куда будет помещен результат - разница</param>
        /// <remarks>
        ///	w[i] = v[i] - w[i].
        /// </remarks>
        public static void Subtract(Vector4 u, Vector4 v, ref Vector4 w)
        {
            w.X = u.X - v.X;
            w.Y = u.Y - v.Y;
            w.Z = u.Z - v.Z;
            w.W = u.W - v.W;
        }

        /// <summary>
        /// Разница вектора и скаляра с помещением результата в другой вектор
        /// </summary>
        /// <param name="u">Уменьшаемый вектор</param>
        /// <param name="s">Вычитаемый скаляр</param>
        /// <param name="v">Вектор, куда будет помещен результат - разница</param>
        /// <remarks>
        /// v[i] = u[i] - s
        /// </remarks>
        public static void Subtract(Vector4 u, double s,  ref Vector4 v)
        {
            v.X = u.X - s;
            v.Y = u.Y - s;
            v.Z = u.Z - s;
            v.W = u.W - s;
        }

        /// <summary>
        /// Разница скаляра и вектора с помещением результата в другой вектор
        /// </summary>
        /// <param name="s">Уменьшаемый скаляр</param>
        /// <param name="u">Вычитаемый вектор</param>
        /// <param name="v">Вектор, куда будет помещен результат - разница</param>
        /// <remarks>
        /// v[i] = s - u[i]
        /// </remarks>
        public static void Subtract(double s, Vector4 u, ref Vector4 v)
        {
            v.X = s - u.X;
            v.Y = s - u.Y;
            v.Z = s - u.Z;
            v.W = s - u.W;
        }

        /// <summary>
        /// Деление вектора на другой вектор
        /// </summary>
        /// <param name="u">Делимый вектор</param>
        /// <param name="v">Вектор делитель</param>
        /// <returns>Частное</returns>
        /// <remarks>
        ///	result[i] = u[i] / v[i].
        /// </remarks>
        public static Vector4 Divide(Vector4 u, Vector4 v)
        {
            return new Vector4(u.X / v.X, u.Y / v.Y, u.Z / v.Z, u.W / v.W);
        }

        /// <summary>
        /// Деление вектора на скаляр
        /// </summary>
        /// <param name="v">Делимый вектор</param>
        /// <param name="s">Делитель - скаляр</param>
        /// <returns>Частное</returns>
        /// <remarks>
        /// result[i] = v[i] / s;
        /// </remarks>
        public static Vector4 Divide(Vector4 v, double s)
        {
            return new Vector4(v.X / s, v.Y / s, v.Z / s, v.W / s);
        }

        /// <summary>
        /// Деление скаляра на вектор
        /// </summary>
        /// <param name="s">Делимое - скалар Vector(s,s,s)</param>
        /// <param name="v">Делитель вектор</param>
        /// <returns>Новый вектор, содержащий частное</returns>
        /// <remarks>
        /// result[i] = s / v[i]
        /// </remarks>
        public static Vector4 Divide(double s, Vector4 v)
        {
            return new Vector4(s / v.X, s / v.Y, s / v.Z, s / v.W);
        }

        /// <summary>
        /// Деление вектора на другой вектор с помещением результата в другой вектор
        /// </summary>
        /// <param name="u">Делимый вектор</param>
        /// <param name="v">Вектор делитель</param>
        /// <param name="w">Вектор, куда будет записан результат - частное</param>
        /// <remarks>
        /// w[i] = u[i] / v[i]
        /// </remarks>
        public static void Divide(Vector4 u, Vector4 v, ref Vector4 w)
        {
            w.X = u.X / v.X;
            w.Y = u.Y / v.Y;
            w.Z = u.Z / v.Z;
            w.W = u.W / v.W;
        }

        /// <summary>
        /// Деление вектора на скаляр с помещением результата в другой вектор
        /// </summary>
        /// <param name="u">Делимый вектор</param>
        /// <param name="s">Делитель скаляр</param>
        /// <param name="v">Вектор, куда будет записан результат - частное</param>
        /// <remarks>
        /// v[i] = u[i] / s
        /// </remarks>
        public static void Divide(Vector4 u, double s, ref Vector4 v)
        {
            v.X = u.X / s;
            v.Y = u.Y / s;
            v.Z = u.Z / s;
            v.W = u.W / s;
        }

        /// <summary>
        /// Деление скаляра на вектор с помещением результата в другой вектор
        /// </summary>
        /// <param name="s">Делимое (скалар)</param>
        /// <param name="u">Делитель (вектор)</param>
        /// <param name="v">Вектор, куда будет записан результат - частное</param>
        /// <remarks>
        /// v[i] = s / u[i]
        /// </remarks>
        public static void Divide(double s, Vector4 u, ref Vector4 v)
        {
            v.X = s / u.X;
            v.Y = s / u.Y;
            v.Z = s / u.Z;
            v.W = s / u.W;
        }

        /// <summary>
        /// Умножение вектора на скаляр
        /// </summary>
        /// <param name="u">Вектор</param>
        /// <param name="s">Скаляр</param>
        /// <returns>Вектор содержащий произведение</returns>
        public static Vector4 Multiply(Vector4 u, double s)
        {
            return new Vector4(u.X * s, u.Y * s, u.Z * s, u.W * s);
        }

        /// <summary>
        /// Умножение вектора на скаляр с помещением результата в другой вектор
        /// </summary>
        /// <param name="u">Вектор</param>
        /// <param name="s">Скаляр</param>
        /// <param name="v">Вектор, куда будет помещено произведение</param>
        public static void Multiply(Vector4 u, double s, ref Vector4 v)
        {
            v.X = u.X * s;
            v.Y = u.Y * s;
            v.Z = u.Z * s;
            v.W = u.W * s;
        }

        /// <summary>
        /// Вычисление скалярного произведения
        /// </summary>
        /// <param name="u">Вектор</param>
        /// <param name="v">Вектор</param>
        /// <returns>Скаляр, содержащий результат скалярного произведения</returns>
        public static double DotProduct(Vector4 u, Vector4 v)
        {
            return (u.X * v.X) + (u.Y * v.Y) + (u.Z * v.Z) + (u.W * v.W);
        }

        /// <summary>
        /// Отрицание вектора - обращение знаков его компонент
        /// </summary>
        /// <param name="v">Исходный вектор</param>
        /// <returns>Обращенный вектор</returns>
        public static Vector4 Negate(Vector4 v)
        {
            return new Vector4(-v.X, -v.Y, -v.Z, -v.W);
        }

        /// <summary>
        /// Проверка на эквивалентность с использованием толерантности по умолчанию
        /// </summary>
        /// <param name="v">Вектор</param>
        /// <param name="u">Вектор</param>
        /// <returns>Истина если вектора эквивалентны, иначе ложь</returns>
        public static bool ApproxEqual(Vector4 v, Vector4 u)
        {
            return ApproxEqual(v, u, Single.Epsilon * 5.0f);
        }

        /// <summary>
        /// Проверка на эквивалентность
        /// </summary>
        /// <param name="v">Вектор</param>
        /// <param name="u">Вектор</param>
        /// <param name="tolerance">Толерантность (возможное отклонение)</param>
        /// <returns>Истина если вектора эквивалентны, иначе ложь</returns>
        public static bool ApproxEqual(Vector4 v, Vector4 u, double tolerance)
        {
            return
                (
                (System.Math.Abs(v.X - u.X) <= tolerance) &&
                (System.Math.Abs(v.Y - u.Y) <= tolerance) &&
                (System.Math.Abs(v.Z - u.Z) <= tolerance) &&
                (System.Math.Abs(v.W - u.W) <= tolerance)
                );
        }

        /// <summary>
        /// Нормализация вектора
        /// </summary>
        /// <param name="v">Вектор для нормализации</param>
        /// <returns>Нормализованный вектор</returns>
        public static Vector4 Normalize(Vector4 v)
        {
            v.Normalize();
            return v;
        }

        #endregion

        #region Методы вектора

        /// <summary>
        /// Нормализация вектора (приведение его к единичному)
        /// </summary>
        public void Normalize()
        {
            double length = GetLength();
            if (length == 0)
            {
                throw new DivideByZeroException("Попытка нормализовать нулевой вектор");
            }

            x /= length;
            y /= length;
            z /= length;
            w /= length;
        }

        /// <summary>
        /// Возвращает единичный вектор, произведенный из этого
        /// </summary>
        /// <returns>Новый вектор (нормализованный клон)</returns>
        public Vector4 GetUnit()
        {
            Vector4 result = new Vector4(this);
            result.Normalize();
            return result;
        }

        /// <summary>
        /// Получение длины вектора
        /// </summary>
        /// <returns>Длина вектора. (Sqrt(X*X + Y*Y + Z*Z + W*W))</returns>
        public double GetLength()
        {
            return (float)System.Math.Sqrt(x * x + y * y + z * z + w * w);
        }

        /// <summary>
        /// Получение квадрата длины вектора
        /// </summary>
        /// <returns>Квадрат длины вектора. (X*X + Y*Y + Z*Z + W*W)</returns>
        public double GetLengthSquared()
        {
            return (x * x + y * y + z * z + w * w);
        }

        #endregion

        #region Переопределенные методы

        /// <summary>
        /// Возвращает хасп-ключ для этого объекта
        /// </summary>
        /// <returns>32-bit хасп-ключ</returns>
        public override int GetHashCode()
        {
            return x.GetHashCode() ^ y.GetHashCode() ^ z.GetHashCode() ^ w.GetHashCode();
        }

        /// <summary>
        /// Проверка эквивалентности с другим объектом
        /// </summary>
        /// <param name="obj">Объект для сравнения</param>
        /// <returns>Истина, если объект эквивалентный, иначе ложь</returns>
        public override bool Equals(object obj)
        {
            if (obj is Vector4)
            {
                Vector4 v = (Vector4)obj;
                return (x == v.X) && (y == v.Y) && (z == v.Z) && (w == v.W);
            }
            return false;
        }

        /// <summary>
        /// Строковое представление объекта
        /// </summary>
        /// <returns>Строка - представление объекта</returns>
        public override string ToString()
        {
            return string.Format("({0}, {1}, {2}, {3})", x, y, z, w);
        }

        #endregion

        #region Операторы сравнения

        /// <summary>
        /// Проверяет эквивалентность двух векторов
        /// </summary>
        /// <param name="u">Левосторонний операнд - вектор</param>
        /// <param name="v">Правосторонний операнд - вектор</param>
        /// <returns>Истина, если два вектора эквивалентны, иначе ложь</returns>
        public static bool operator ==(Vector4 u, Vector4 v)
        {
            return ValueType.Equals(u, v);
        }

        /// <summary>
        /// Проверяет на отличность двух векторов
        /// </summary>
        /// <param name="u">Левосторонний операнд - вектор</param>
        /// <param name="v">Правосторонний операнд - вектор</param>
        /// <returns>Истина, если два вектора отличны, иначе ложь</returns>
        public static bool operator !=(Vector4 u, Vector4 v)
        {
            return !ValueType.Equals(u, v);
        }

        /// <summary>
        /// Проверяет больше ли все компоненты одного вектора всех компонент другого
        /// </summary>
        /// <param name="u">Левосторонний операнд - вектор</param>
        /// <param name="v">Правосторонний операнд - вектор</param>
        /// <returns>
        /// Истина, если все компоненты левого операнда 
        /// окажутся больше другого, иначе ложь
        /// </returns>
        public static bool operator >(Vector4 u, Vector4 v)
        {
            return (
                (u.x > v.x) &&
                (u.y > v.y) &&
                (u.z > v.z) &&
                (u.w > v.w));
        }

        /// <summary>
        /// Проверяет меньше ли все компоненты одного вектора всех компонент другого
        /// </summary>
        /// <param name="u">Левосторонний операнд - вектор</param>
        /// <param name="v">Правосторонний операнд - вектор</param>
        /// <returns>
        /// Истина, если все компоненты левого операнда 
        /// окажутся меньше другого, иначе ложь
        /// </returns>
        public static bool operator <(Vector4 u, Vector4 v)
        {
            return (
                (u.x < v.x) &&
                (u.y < v.y) &&
                (u.z < v.z) &&
                (u.w < v.w));
        }

        /// <summary>
        /// Проверяет больше или равны компоненты одного вектора компонентам другого
        /// </summary>
        /// <param name="u">Левосторонний операнд - вектор</param>
        /// <param name="v">Правосторонний операнд - вектор</param>
        /// <returns>
        /// Истина, если все компоненты левого операнда 
        /// окажутся больше или равны другому, иначе ложь
        /// </returns>
        public static bool operator >=(Vector4 u, Vector4 v)
        {
            return (
                (u.x >= v.x) &&
                (u.y >= v.y) &&
                (u.z >= v.z) &&
                (u.w >= v.w));
        }

        /// <summary>
        /// Проверяет меньше или равны компоненты одного вектора компонентам другого
        /// </summary>
        /// <param name="u">Левосторонний операнд - вектор</param>
        /// <param name="v">Правосторонний операнд - вектор</param>
        /// <returns>
        /// Истина, если все компоненты левого операнда 
        /// окажутся меньше или равны другому, иначе ложь
        /// </returns>
        public static bool operator <=(Vector4 u, Vector4 v)
        {
            return (
                (u.x <= v.x) &&
                (u.y <= v.y) &&
                (u.z <= v.z) &&
                (u.w <= v.w));
        }

        #endregion

        #region Унарные операторы

        /// <summary>
        /// Обращение знака компонент вектора
        /// </summary>
        /// <param name="v">Вектор</param>
        /// <returns>Новый объект с обращенными значениями</returns>
        public static Vector4 operator -(Vector4 v)
        {
            return Vector4.Negate(v);
        }

        #endregion

        #region Бинарные операторы

        /// <summary>
        /// Сложение двух векторов
        /// </summary>
        /// <param name="u">Вектор, левое слагаемое</param>
        /// <param name="v">Вектор, правое слагаемое</param>
        /// <returns>Вектор, содержит сумму</returns>
        public static Vector4 operator +(Vector4 u, Vector4 v)
        {
            return Vector4.Add(u, v);
        }

        /// <summary>
        /// Складывает вектор и скаляр
        /// </summary>
        /// <param name="v">Вектор, левон слагаемое</param>
        /// <param name="s">Скаляр, правое слагаемое</param>
        /// <returns>Вектор, содержит сумму</returns>
        public static Vector4 operator +(Vector4 v, double s)
        {
            return Vector4.Add(v, s);
        }

        /// <summary>
        /// Складывает скаляр и вектор 
        /// </summary>
        /// <param name="s">Скаляр, левое слагаемое</param>
        /// <param name="v">Вектор, правое слагаемое</param>
        /// <returns>Вектор, содержит сумму</returns>
        public static Vector4 operator +(double s, Vector4 v)
        {
            return Vector4.Add(v, s);
        }

        /// <summary>
        /// Разница двух векторов
        /// </summary>
        /// <param name="u">Вектор, уменьшаемое</param>
        /// <param name="v">Вектор, вычитаемое</param>
        /// <returns>Вектор, содержит разницу</returns>
        /// <remarks>
        ///	result[i] = v[i] - w[i].
        /// </remarks>
        public static Vector4 operator -(Vector4 u, Vector4 v)
        {
            return Vector4.Subtract(u, v);
        }

        /// <summary>
        /// Вычитает скаляр из вектора
        /// </summary>
        /// <param name="v">Вектор, уменьшаемое</param>
        /// <param name="s">Скаляр, вычитаемое</param>
        /// <returns>Вектор, содержит разницу</returns>
        /// <remarks>
        /// result[i] = v[i] - s
        /// </remarks>
        public static Vector4 operator -(Vector4 v, double s)
        {
            return Vector4.Subtract(v, s);
        }

        /// <summary>
        /// Вычитает вектор из скаляра, который задает вектор (s,s,s,s)
        /// </summary>
        /// <param name="s">Скаляр, уменьшаемое</param>
        /// <param name="v">Вектор, вычитаемое</param>
        /// <returns>Вектор, содержит разницу</returns>
        /// <remarks>
        /// result[i] = s - v[i]
        /// </remarks>
        public static Vector4 operator -(double s, Vector4 v)
        {
            return Vector4.Subtract(s, v);
        }

        /// <summary>
        /// Умножение вектора на скаляр
        /// </summary>
        /// <param name="v">Вектор</param>
        /// <param name="s">Скаляр</param>
        /// <returns>Вектор, содержит произведение</returns>
        public static Vector4 operator *(Vector4 v, double s)
        {
            return Vector4.Multiply(v, s);
        }

        /// <summary>
        /// Умножение скаляра на вектор
        /// </summary>
        /// <param name="s">Скаляр</param>
        /// <param name="v">Вектор</param>
        /// <returns>Вектор, содержит произведение</returns>
        public static Vector4 operator *(double s, Vector4 v)
        {
            return Vector4.Multiply(v, s);
        }

        /// <summary>
        /// Деление вектора на скаляр
        /// </summary>
        /// <param name="v">Вектор, делимое</param>
        /// <param name="s">Скаляр, делитель</param>
        /// <returns>Вектор, содержит частное</returns>
        /// <remarks>
        /// result[i] = v[i] / s;
        /// </remarks>
        public static Vector4 operator /(Vector4 v, double s)
        {
            return Vector4.Divide(v, s);
        }

        /// <summary>
        /// Деление скаляра на вектор
        /// </summary>
        /// <param name="s">Скаляр, делимое</param>        
        /// <param name="v">Вектор, делитель</param>
        /// <returns>Вектор, содержит частное</returns>
        /// <remarks>
        /// result[i] = v[i] / s;
        /// </remarks>
        public static Vector4 operator /(double s, Vector4 v)
        {
            return Vector4.Divide(s, v);
        }

        #endregion

        #region Операторы доступа через индексы

        /// <summary>
        /// Индексы ( [x, y] ).
        /// </summary>
        public double this[int index]
        {
            get
            {
                switch (index)
                {
                    case 0:
                        return x;
                    case 1:
                        return y;
                    case 2:
                        return z;
                    case 3:
                        return w;
                    default:
                        throw new IndexOutOfRangeException();
                }
            }
            set
            {
                switch (index)
                {
                    case 0:
                        x = value;
                        break;
                    case 1:
                        y = value;
                        break;
                    case 2:
                        z = value;
                        break;
                    case 3:
                        w = value;
                        break;
                    default:
                        throw new IndexOutOfRangeException();
                }
            }

        }

        #endregion

        #region Операторы конвертации

        /// <summary>
        /// Конвертирует вектор в масив вещественных одинарной точности
        /// </summary>
        /// <param name="v">Вектор</param>
        /// <returns>Массив вещественных одинарной точности с компнентами вектора</returns>
        public static explicit operator double[](Vector4 v)
        {
            double[] array = new double[4];
            array[0] = v.X;
            array[1] = v.Y;
            array[2] = v.Z;
            array[3] = v.W;
            return array;
        }

        #endregion
    }
}